package com.limh.gobang.service.server

import android.util.Log
import com.limh.gobang.service.WebConfiguration
import com.limh.gobang.service.resource.IResourceUriHandler
import com.limh.gobang.service.utils.HttpContext
import com.limh.gobang.service.utils.StreamToolkit
import java.io.IOException
import java.net.InetSocketAddress
import java.net.ServerSocket
import java.net.Socket
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors


/**
 * @author limh
 * @function
 * @date 2018/4/27 14:39
 */
class HttpServer(private var webConfig: WebConfiguration) {

    private val TAG = "HttpServer"

    private var isEnable = true
    private var socket: ServerSocket? = null
    private var threadPool: ExecutorService? = null
    private var resourceHandlers: MutableSet<IResourceUriHandler>? = null

    init {
        threadPool = Executors.newCachedThreadPool()
        resourceHandlers = HashSet()
    }

    /**
     * 启动服务器
     */
    fun startASync() {
        Log.i(TAG, "startASync")
        isEnable = true
        Thread(Runnable {
            doProcSync()
        }).start()
    }

    fun stopASync() {
        if (!isEnable) {
            return
        }
        isEnable = false
        socket!!.close()
    }

    private fun doProcSync() {
        try {
            val intSocketAddress = InetSocketAddress(webConfig!!.port)
            socket = ServerSocket()
            socket!!.bind(intSocketAddress)
            Log.i(TAG, "doProcSync")
            while (isEnable) {
                val remotePeer = socket!!.accept()
                threadPool!!.submit({
                    Log.d(TAG, "remote address=" + remotePeer.remoteSocketAddress.toString())
                    onAcceptRemotePeer(remotePeer)
                })
            }
        } catch (e: IOException) {
            Log.e(TAG, "doProcSync=" + e.toString())
        }
    }

    fun registerResourceHandler(hander: IResourceUriHandler) {
        resourceHandlers!!.add(hander)
    }

    private fun onAcceptRemotePeer(remotePeer: Socket?) {
        try {
            val httpContext = HttpContext()
            httpContext.underlySocket = remotePeer

            val nis = remotePeer!!.getInputStream()

            var headLine = StreamToolkit.readLine(nis)!!.split(" ")[1]
            val requestUri = headLine
            Log.i(TAG, "requestUri=$requestUri")
            while (StreamToolkit.readLine(nis).apply { headLine = this!! } != null) {
                if (headLine == "\r\n") {
                    Log.d(TAG, "header line finish")
                    break
                }
                val str = headLine.split(": ")
                if (str.size > 1)
                    httpContext.addRequestHeader(str[0], str[1])
                Log.i(TAG, "header line=$headLine")
            }

            for (hander in resourceHandlers!!) {
                if (!hander.accept(requestUri)) {
                    continue
                }
                hander.handle(requestUri, httpContext)
            }
        } catch (e: IOException) {
            Log.e(TAG, "onAcceptRemotePeer:" + e.toString())
        } finally {
            remotePeer!!.close()
        }
    }
}
